//订阅发布类
class Dep{
    constructor(){
        this.container = []
    }
    subscribe(watcher){//订阅
        this.container.push(watcher)
    }
    notify(value){//发布
        this.container.forEach((watcher)=>{
            //wathcer上有对应的节点，属性，示例，回调函数
            watcher.update(value)
        })
    }
}
//观察者类
class Watcher{
    constructor(node,express,vm,callback){
        this.node = node
        this.express = express
        this.vm = vm
        this.callback = callback
        this.oldValue = this.getValue(vm,express)
    }
    getValue(vm,express){
        Dep.target = this
        let arr = express.split('.')
        let value = arr.reduce((obj,current)=>{
           return obj = obj[current]
        },vm)
        Dep.target = null
        return value
    }
    update(value){
        this.callback(value)
    }
}
class Observer{
    constructor(vm){
        this.$vm = vm
        //将options.data上的所有的属性代理到vm上
        this.proxyOptionsToVm(vm.$options.data,vm)
        //将计算属性代理到实例上
        this.proxyComputedToVm(vm.$options.computed,vm)
        //递归代理data上的所有层级属性
        this.proxyData(vm.$options.data)
    }
    proxyOptionsToVm(data,vm){
        Object.keys(data).forEach((key)=>{
            Object.defineProperty(vm,key,{
                get(){
                    return data[key]
                },
                set(newValue){
                    data[key] = newValue
                }
            })
        })
    }
    proxyComputedToVm(computed,vm){
        Object.keys(computed).forEach((key)=>{
            Object.defineProperty(vm,key,{
                get(){
                    return computed[key].call(vm)
                },
                set(){
                }
            })
        })
    }
    proxyData(data){
        Object.keys(data).forEach((key)=>{
            this.midProxyDataFn(data,key,data[key])
        })
    }
    midProxyDataFn(obj,key,value){
        if(typeof value === 'object'){
            this.proxyData(value)
        }
        let dep = new Dep()
        Object.defineProperty(obj,key,{
            get(){
                if(Dep.target){
                    dep.subscribe(Dep.target)
                }
               
                return value
            },
            set(newValue){
                if(value!==newValue){
                    value = newValue
                    dep.notify(newValue)
                }
                
            }
        })
    }
}